package com.miao.im.support.exception;

import com.miao.im.common.ApiResult;
import com.miao.im.common.BizCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolationException;
import java.io.IOException;
import java.util.List;

/**
 * @author: miaoguoxin
 * @date: 2020/4/8 11:22
 */
@RestControllerAdvice
@Slf4j
public class WebGlobalExceptionResolver {


    /**
     * 表单参数校验
     * @author miaoguoxin
     * @date 2020/7/10
     */
    @ExceptionHandler({BindException.class})
    public ApiResult<?> handleFormArgException(BindException e) throws IOException {
        return ApiResult.err(BizCode.PARAMS_ERROR, errorMessage(e.getBindingResult()));
    }

    /**
     * 方法参数校验处理，配合validator
     */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public ApiResult<?> handleMethodArgException(MethodArgumentNotValidException e) throws IOException {
        return ApiResult.err(BizCode.PARAMS_ERROR, errorMessage(e.getBindingResult()));
    }


    /**
     * 单参数校验异常处理
     */
    @ExceptionHandler({ConstraintViolationException.class})
    public ApiResult<?> handleConstraintViolationException(ConstraintViolationException e) throws IOException {
        return ApiResult.err(BizCode.PARAMS_ERROR, e.getMessage());
    }

    /**
     * 415处理
     */
    @ExceptionHandler({HttpMediaTypeNotSupportedException.class})
    public ApiResult<?> handle415Exception(HttpMediaTypeNotSupportedException e) throws IOException {
        return ApiResult.err(BizCode.UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type");
    }

    /**
     * 400处理
     */
    @ExceptionHandler({HttpMessageNotReadableException.class})
    public ApiResult<?> handle400Exception(HttpMessageNotReadableException e) throws IOException {
        log.error("参数有误：{}", e.getMessage());
        return ApiResult.err(BizCode.INVALID_REQUEST, "Bad Request");
    }

    /**
     * 405处理
     */
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    public ApiResult<?> handle405Exception(HttpRequestMethodNotSupportedException e) throws IOException {
        return ApiResult.err(BizCode.METHOD_NOT_ALLOWED, "Method Not Allowed");
    }


    @ExceptionHandler({IllegalArgumentException.class})
    public ApiResult<?> handleIllegalArgumentException(IllegalArgumentException e) {
        log.error("IllegalArgumentException:{}", e.getMessage());
        return ApiResult.err(BizCode.PARAMS_ERROR, e.getMessage());
    }

    /**
     * 权限异常处理
     */
    @ExceptionHandler({AuthenticationException.class})
    public ApiResult<?> handlerAuthException(AuthenticationException e) throws IOException {
        return ApiResult.err(e.getCode(), e.getMessage());
    }

    /**
     * 业务异常处理
     */
    @ExceptionHandler({BizException.class})
    public ApiResult<?> handlerBusinessException(BizException e) throws IOException {
        return ApiResult.err(e.getCode(), e.getMessage());
    }


    /**
     * 处理未自定义的异常
     */
    @ExceptionHandler({Exception.class})
    public ApiResult<?> handlerOtherException(Exception e) throws IOException {
        log.error("其他异常:", e);
        return ApiResult.err(BizCode.SERVER_ERROR, "系统异常！");
    }


    private static String errorMessage(BindingResult result) {
        if (result == null) {
            return "";
        }
        List<ObjectError> allErrors = result.getAllErrors();
        return allErrors.stream()
                .findFirst()
                .map(DefaultMessageSourceResolvable::getDefaultMessage)
                .orElse("未知参数错误");
    }

}
